package com.ssm.custom.servlet;

import com.ssm.custom.anno.ResponseBody;
import com.ssm.custom.controller.TestController;
import com.ssm.custom.handler.InvocationHandler;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.*;
import java.util.logging.Logger;

/**
 * @author: Hsiao
 * @date: 2023-11-22
 * @description:
 */
public class DispatcherServlet extends HttpServlet {

    Logger log = Logger.getLogger("com.ssm.custom.servlet.DispatcherServlet");
    private static Map<String, InvocationHandler> handlerMap;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        StringBuffer requestUrl = req.getRequestURL();

        String path  = new String(requestUrl).replace("http://localhost:"+req.getServerPort(),"");
        log.info("请求路径为：" + path);

        // todo: if path = *.html, can't get handler. NullPointerException
        InvocationHandler handler = handlerMap.get(path);
        Method method = handler.getMethod();

        boolean hasResponseBody = method.isAnnotationPresent(ResponseBody.class);
        // json
        if (hasResponseBody) {
            try {
                Object body = method.invoke(handler.getObject());
                resp.getWriter().print(body.toString());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        // view
        else {
            String url = "http://localhost:" + req.getServerPort() + "/" + req.getContextPath();
            String prefix = "";
            String suffer = ".html";
            try {
                String result = (String) method.invoke(handler.getObject());
                if (result.contains("forward:")) {
                    req.getRequestDispatcher("index.html").forward(req, resp);
                }
                if (result.contains("redirect:")) {
                    resp.sendRedirect(url + prefix + result.replace("redirect:", "") + suffer);
                }
                if (!result.contains("forward:")&&!result.contains("redirect:")){
                    resp.sendRedirect(url+prefix+result+suffer);
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 初始化：主要是扫描controller中的方法
     **/
    @Override
    public void init() throws ServletException {
        log.info("项目启动");

        String basePackage = "com.ssm.custom.controller";
        Set<Class<?>> classSet = controllerScan(basePackage);
        classSet.add(TestController.class);

        HandlerMapping handlerMapping = new HandlerMapping();
        handlerMap = handlerMapping.urlMapping(classSet);

    }

    /**
     * 扫描controller
     **/
    private static Set<Class<?>> controllerScan(String basePackage) {

        HashSet<Class<?>> set = new HashSet<>();

        String baseDir = basePackage.replace(".", "/");
        try {
            Enumeration<URL> resources = DispatcherServlet.class.getClassLoader().getResources(baseDir);
            while (resources.hasMoreElements()) {
                URL url = resources.nextElement();
                File directory = new File(url.getFile());
                for (File file : Objects.requireNonNull(directory.listFiles())) {
                    set.add(Class.forName(basePackage + "." + file.getName().substring(0, file.getName().length() - 6)));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return set;
    }

    public static void main(String[] args) {
        controllerScan("com.ssm.custom.controller");
    }
}
